//
// client.c (Corrected)
//

// --- NECESSARY HEADERS ADDED ---
#include <stdio.h>      // For printf, perror
#include <stdlib.h>     // For free
#include <string.h>     // For strlen
#include <stdbool.h>    // For bool type
#include <unistd.h>     // For read, write, close
#include <sys/socket.h> // For socket
#include <arpa/inet.h>  // For sockaddr_in, inet_pton

// --- PROJECT-SPECIFIC HEADERS ---
#include "../common/common.h"
#include "../lib/cJSON.h"
#include "../common/rpc_protocol.h"
// --------------------------------

/**
 * @brief Core client function to perform an RPC call.
 * Encapsulates socket creation, connection, sending, and receiving.
 * @param request_str The JSON-RPC request string to send.
 * @param response_buf Buffer to store the server's response.
 * @param response_buf_size The size of the response buffer.
 * @return true on success, false on any network or communication error.
 */
static bool perform_rpc_call(const char *request_str, char *response_buf,
                             size_t response_buf_size)
{
  int sock = 0;
  struct sockaddr_in serv_addr;

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
    perror("Socket creation error");
    return false;
  }

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(SERVER_PORT);

  if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
  {
    perror("Invalid address/ Address not supported");
    close(sock);
    return false;
  }

  if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
  {
    perror("Connection Failed");
    close(sock);
    return false;
  }

  send(sock, request_str, strlen(request_str), 0);
  printf("Client: Sent request:\n%s\n", request_str);

  ssize_t valread = read(sock, response_buf, response_buf_size - 1);
  if (valread > 0)
  {
    response_buf[valread] = '\0';
  }
  else
  {
    if (valread < 0)
    {
      perror("Read error");
    }
    else
    {
      printf("Server closed connection.\n");
    }
    close(sock);
    return false;
  }

  close(sock);
  return true;
}

int main(void)
{
  char response_buffer[MAX_BUFFER_SIZE];
  int32_t request_id = 1;

  // --- Call 1: add(10, 25) ---
  printf("--- RPC Call: add ---\n");
  char *request1 = create_json_rpc_request("add", request_id++, "ii", 10, 25);
  if (request1 != NULL &&
      perform_rpc_call(request1, response_buffer, sizeof(response_buffer)))
  {
    printf("Client: Received response:\n%s\n\n", response_buffer);
  }
  free(request1); // MISRA Deviation: free()

  // --- Call 2: getUserInfo("Alice") ---
  printf("--- RPC Call: getUserInfo ---\n");
  char *request2 = create_json_rpc_request("getUserInfo", request_id++, "s", "Alice");
  if (request2 != NULL &&
      perform_rpc_call(request2, response_buffer, sizeof(response_buffer)))
  {
    printf("Client: Received response:\n%s\n\n", response_buffer);
  }
  free(request2);

  // --- Call 3: Variadic sumAndPrint(1.1, "hello", 2.2, 3) ---
  printf("--- RPC Call: sumAndPrint (variadic) ---\n");
  char *request3 = create_json_rpc_request("sumAndPrint", request_id++, "dsdi", 1.1, "world", 2.2, 3);
  if (request3 != NULL &&
      perform_rpc_call(request3, response_buffer, sizeof(response_buffer)))
  {
    printf("Client: Received response:\n%s\n\n", response_buffer);
  }
  free(request3);

  // --- Call 4: Passing a struct to processUserProfile ---
  printf("--- RPC Call: processUserProfile (with struct) ---\n");
  UserProfile my_profile = {"Bob", 42, "New York"};
  // The 'S' format specifier tells our function to serialize the struct.
  char *request4 = create_json_rpc_request("processUserProfile", request_id++, "S", &my_profile);
  if (request4 != NULL &&
      perform_rpc_call(request4, response_buffer, sizeof(response_buffer)))
  {
    printf("Client: Received response:\n%s\n\n", response_buffer);
  }
  free(request4);

  // --- Exception Handling Demo: Calling a non-existent method ---
  printf("--- RPC Call: Non-existent method (exception handling) ---\n");
  char *request_err = create_json_rpc_request("nonExistentMethod", request_id++, "");
  if (request_err != NULL &&
      perform_rpc_call(request_err, response_buffer, sizeof(response_buffer)))
  {
    printf("Client: Received error response:\n%s\n\n", response_buffer);
  }
  free(request_err);

  return 0;
}
